<!--
 * @Description:  使用定时器播放
 * @Author: wang_k
 * @Date: 2025-08-19 18:58:52
 * @LastEditTime: 2025-08-29 16:33:32
 * @FilePath: /note/src/views/Ceshi/components/end.vue
-->
<template>
  <div class="rock_chart">
    <div title="实际施工进度" style="margin-bottom: 10px">
      <div class="title_right_content">
        <div class="right_title_info">
          <div class="legend">
            <div
              class="legend-item"
              v-for="(item, index) in legendData"
              :key="index"
            >
              <span
                class="legend-dot"
                :style="{
                  background: item.color,
                }"
              ></span>
              <span class="legend-text">{{ item.text }}</span>
            </div>
            施工部位：开挖支护
          </div>
        </div>
      </div>
    </div>
    <div class="trend_chart_box">
      <div class="chart_box_left">
        <div
          class="panel-item"
          v-for="item in panelData"
          :key="item.label"
          :style="`background:${item.color}`"
        >
          <div>{{ item.label }}</div>
          <div>{{ item.value }}m</div>
        </div>
      </div>
      <div class="chart_box_right">
        <div class="progress-box" @click="handlePositionLine">
          <div class="progress-content">
            <div
              class="progress-history"
              :style="{
                width: history_width + '%',
              }"
            >
              历史态势
            </div>
            <div
              class="progress-future"
              :style="{
                width: 100 - history_width + '%',
              }"
            >
              未来态势
            </div>
          </div>
          <div class="progress-scale">
            <div
              class="progress-scale-item"
              v-for="(item, index) in xData"
              :key="item.value"
              :style="{
                width: item.width + '%',
              }"
            >
              <div
                class="progress-scale-line"
                v-show="index !== 0 && index !== xData.length - 1"
              ></div>
              <div
                class="progress-scale-son"
                v-show="index !== 0 && index !== xData.length - 1"
              >
                {{ dayFormat(item.value) }}
              </div>
            </div>
          </div>
          <div
            class="marking-line"
            :style="{
              left: currentPosition + '%',
            }"
          >
            <span class="line-row1">{{ markingData.date }}</span>
            <span class="line-row2">{{ markingData.meter }}</span>
          </div>
        </div>
        <div class="play-content">
          <div class="play-button">
            <div class="play" @click="handleBackoff">
              <img src="@/assets/img/Cbe/play_left.png" alt="后退" />
            </div>
            <div class="play play1" @click="handlePlay">
              <img
                :src="isPlaying ? playImg.pause : playImg.play"
                alt="播放/暂停"
              />
            </div>
            <div class="play" @click="handleSpeed">
              <img src="@/assets/img/Cbe/play_right.png" alt="前进" />
            </div>
          </div>
          <div class="play-select">
            播放速度
            <fks-select
              style="width: 100px; margin-left: 10px"
              v-model="playbackSpeed"
              placeholder="请选择"
            >
              <fks-option
                v-for="item in playbackSpeedOptions"
                :key="item.value"
                :label="item.label"
                :value="item.value"
              >
              </fks-option>
            </fks-select>
            <fks-button
              style="margin-left: 10px"
              icon="fks-icon-reset"
              @click="handleReset"
            ></fks-button>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>

<script>
export default {
  name: 'ConstructionProgressChart',
  data() {
    return {
      legendData: [
        {
          color: '#78CD78',
          text: '已完成',
        },
        {
          color: '#BFBFBF',
          text: '未开始',
        },
      ],
      panelData: [
        {
          label: '设计长度',
          value: '1530',
          color:
            'linear-gradient(284deg,rgba(0, 107, 237, 0) 3%,rgba(0, 107, 237, 0.15) 95%)',
        },
        {
          label: '2024年实际完成',
          value: '1530',
          color:
            'linear-gradient(284deg, rgba(149, 125, 243, 0) 3%, rgba(149, 125, 243, 0.15) 95%)',
        },
        {
          label: '2025年计划完成',
          value: '1530',
          color:
            'linear-gradient(284deg, rgba(249, 175, 85, 0) 3%, rgba(249, 175, 85, 0.15) 95%)',
        },
      ],
      markingData: {
        date: '2024-08-01',
        meter: '123m',
      },
      initcurrentPosition: '',
      currentPosition: '',
      history_width: 40,
      isPlaying: false,
      playImg: {
        play: require('@/assets/img/Cbe/play.png'),
        pause: require('@/assets/img/Cbe/pause.png'),
      },
      timer: null, // 定时器ID
      interval: 50, // 定时器间隔时间(ms)，控制刷新频率

      playbackSpeed: 1, // 播放速度控制，数字类型
      playEndDate: '2024-11-01',
      startPosition: 0, // 播放起点位置
      endPosition: 0, // 播放终点位置
      step: 0.1, // 基础步长
      playbackSpeedOptions: [
        // { value: '1', label: '1' },
        // { value: '0.5', label: '2' },
        // { value: '0.3', label: '3' },
        // { value: '2', label: '0.5' },
        { value: 1, label: '1' },
        { value: 2, label: '2' },
        { value: 3, label: '3' },
        { value: '0.5', label: '0.5' },
      ],
    };
  },
  computed: {
    xData() {
      const dayArr = this.generateMonthlyFirstDays();
      if (dayArr.length < 2) return [];

      const startTime = this.$dayjs(dayArr[0]).valueOf();
      const endTime = this.$dayjs(dayArr[dayArr.length - 1]).valueOf();
      const totalDuration = endTime - startTime;
      if (totalDuration <= 0) return [];

      const intervalWidths = [];
      for (let i = 0; i < dayArr.length - 1; i++) {
        const currentTime = this.$dayjs(dayArr[i]).valueOf();
        const nextTime = this.$dayjs(dayArr[i + 1]).valueOf();
        const intervalDuration = nextTime - currentTime;
        const widthRatio = (intervalDuration / totalDuration) * 100;
        intervalWidths.push(widthRatio);
      }

      const sumPrevWidths = intervalWidths.reduce((sum, w) => sum + w, 0);
      const lastWidth = 100 - sumPrevWidths;
      intervalWidths.push(lastWidth);

      const res = dayArr.map((item, index) => ({
        value: item,
        width: intervalWidths[index].toFixed(6),
      }));

      return res;
    },
    // 根据播放速度计算实际步长
    actualStep() {
      return this.step * this.playbackSpeed;
    },
  },
  watch: {
    playbackSpeed(newSpeed) {
      // 播放中改变速度时，重新启动定时器以应用新速度
      if (this.isPlaying) {
        this.pauseAnimation();
        this.startAnimation();
      }
    },
  },
  created() {},
  mounted() {
    this.handlerProgressChange();
  },
  methods: {
    handleSpeed() {
      this.currentPosition += 2;
      if (this.currentPosition >= this.endPosition) {
        this.currentPosition = this.endPosition;
      }
      this.updateMarkingData();
      this.calculatePlayRange();
    },
    handleBackoff() {
      this.currentPosition -= 2;
      if (this.currentPosition <= this.startPosition) {
        this.currentPosition = this.startPosition;
      }
      this.updateMarkingData();
      this.calculatePlayRange();
    },
    /* 点击任意位置播放 */
    handlePositionLine(event) {
      // return;
      console.log('event:', event);

      const clickX = event.offsetX;
      const boxWidth = document.querySelector('.progress-box').clientWidth;
      const clickRatio = clickX / boxWidth;
      this.currentPosition = clickRatio * 100;
      this.updateMarkingData();
      this.calculatePlayRange();
    },
    dayFormat(value) {
      return this.$dayjs(value).format('MM-DD');
    },
    calculateMarkerPosition(is = true, markDate = this.markingData.date) {
      const timeline = this.xData.map((item) => item.value);
      if (timeline.length === 0) return;

      const startDate = timeline[0];
      const startTime = this.$dayjs(startDate).valueOf();
      const endTime = this.$dayjs(timeline[timeline.length - 1]).valueOf();
      const totalDuration = endTime - startTime;

      const targetTime = this.$dayjs(markDate).valueOf();
      const elapsedTime = targetTime - startTime;
      const timeRatio = Math.min(1, Math.max(0, elapsedTime / totalDuration));

      if (is) {
        this.currentPosition = timeRatio * 100;
        this.initcurrentPosition = timeRatio * 100;
      } else {
        return timeRatio * 100;
      }
    },
    calculatePlayRange() {
      const timeline = this.xData.map((item) => item.value);
      if (timeline.length < 2) return;

      const startTime = this.$dayjs(timeline[0]).valueOf();
      const endTime = this.$dayjs(timeline[timeline.length - 1]).valueOf();
      const totalDuration = endTime - startTime;
      if (totalDuration === 0) return;

      const startPlayTime = this.$dayjs(this.markingData.date).valueOf();
      this.startPosition = Math.min(
        100,
        Math.max(0, ((startPlayTime - startTime) / totalDuration) * 100),
      );
      console.log(this.startPosition, 'startPosition');

      const endPlayTime = this.$dayjs(this.playEndDate).valueOf();
      this.endPosition = Math.min(
        100,
        Math.max(0, ((endPlayTime - startTime) / totalDuration) * 100),
      );
    },
    handlePlay() {
      if (this.isPlaying) {
        this.pauseAnimation();
      } else {
        this.startAnimation();
      }
      this.isPlaying = !this.isPlaying;
    },
    handleReset() {
      this.pauseAnimation();
      this.isPlaying = false;
      this.currentPosition = this.startPosition;
      this.updateMarkingData();
    },
    // 使用setInterval实现动画
    startAnimation() {
      // 清除可能存在的定时器
      if (this.timer) {
        clearInterval(this.timer);
      }

      // 如果已到达终点，重置位置
      if (this.currentPosition >= this.endPosition) {
        this.currentPosition = this.startPosition;
      }

      // 设置定时器
      this.timer = setInterval(() => {
        // 计算下一步位置
        let nextPosition = this.currentPosition + this.actualStep;
        console.log(
          'nextPosition:',
          nextPosition,
          this.currentPosition,
          this.actualStep,
        );

        // 检查是否到达终点
        if (nextPosition >= this.endPosition) {
          nextPosition = this.endPosition;
          this.pauseAnimation();
          this.isPlaying = false;
        }

        // 更新位置并刷新显示
        this.currentPosition = nextPosition;
        this.updateMarkingData();
      }, this.interval);
    },
    // 暂停动画
    pauseAnimation() {
      if (this.timer) {
        clearInterval(this.timer);
        this.timer = null;
      }
    },
    updateMarkingData() {
      const totalPoints = this.xData.length;
      if (totalPoints === 0) return;

      const progressRatio = this.currentPosition / 100;
      let pointIndex = Math.floor(progressRatio * totalPoints);
      pointIndex = Math.min(totalPoints - 1, Math.max(0, pointIndex));

      if (this.xData[pointIndex]) {
        // this.markingData.date = this.dayFormat(this.xData[pointIndex].value);
      }

      const totalMeters = parseInt(this.panelData[0].value);
      const currentMeters = Math.floor(totalMeters * progressRatio);
      // this.markingData.meter = `${currentMeters}m`;
    },
    selectProject(node) {
      this.nodeData = node;
    },
    handlerProgressChange(data) {
      this.calculateMarkerPosition();
      this.calculatePlayRange();
    },
    zoomHandle() {
      window.eventHub.$emit('onProgressChange', { isShow: false });
    },
    generateMonthlyFirstDays(inputDate = '2024-05-05') {
      const start = this.$dayjs(inputDate).startOf('month');
      const end = this.$dayjs().endOf('month');

      const firstDayList = [];
      let current = start;

      while (current.isBefore(end) || current.isSame(end, 'month')) {
        firstDayList.push(current.format('YYYY-MM-DD'));
        current = current.add(1, 'month');
      }

      if (!firstDayList.includes(end.format('YYYY-MM-DD'))) {
        firstDayList.push(end.format('YYYY-MM-DD'));
      }

      return firstDayList;
    },
  },
  beforeDestroy() {
    // 组件销毁时清除定时器
    this.pauseAnimation();
  },
};
</script>

<style scoped>
.play-content {
  display: flex;
  align-items: center;
  font-size: 14px;
  justify-content: flex-end;
}
.play-select {
  display: flex;
  align-items: center;
  margin-left: 50px;
  font-size: 14px;
}
.play-button {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  .play {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
    border-radius: 20px;
    box-sizing: border-box;
    border: 1.5px solid rgba(0, 107, 237, 0.3);
    margin-left: 10px;
    cursor: pointer;
    img {
      width: 50%;
      height: 50%;
    }
  }
  .play1 {
    width: 32px;
    height: 32px;
  }
}
.rock_chart {
  position: absolute;
  bottom: 74px;
  left: 23%;
  width: 55%;
  height: 25%;
  padding: 15px;
  border-width: 3px;
  border-style: solid;
  border-color: white;
  border-radius: 12px;
  background-color: #f4f7fa;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
}

.title_right_content {
  display: flex;
  align-items: center;

  .right_title_info {
    margin-right: 15px;
    font-size: 12px;
    color: #666666;
  }

  img {
    width: 14px;
    height: 14px;
    cursor: pointer;
  }
}

.trend_chart_box {
  display: flex;
  justify-content: space-between;
  width: 100%;
  height: calc(100% - 30px);
  position: relative;
  .chart_box_left {
    display: flex;
    flex-direction: column;
    justify-content: space-around;
    width: 140px;
    .panel-item {
      display: flex;
      flex-direction: column;
      align-items: flex-start;
      justify-content: center;
      padding-left: 12px;
      width: 125px;
      height: 54px;
      font-size: 14px;
      border-radius: 4px;
      box-sizing: border-box;
      border: 1px solid rgba(0, 107, 237, 0.2);
    }
  }
  .chart_box_right {
    display: flex;
    flex-direction: column;
    justify-content: space-around;
    width: calc(100% - 165px);
    .progress-box {
      position: relative;
      display: flex;
      flex-direction: column;
      width: 100%;
      height: 80%;
      justify-content: center;
      padding: 0;
      margin: 0;
    }
    .progress-content {
      display: flex;
      width: 100%;
      height: 20px;
      font-size: 12px;
      background: #999;
      border-radius: 20px;
      color: #fff;
      overflow: hidden;
    }
    .progress-history {
      display: flex;
      align-items: center;
      justify-content: center;
      background: linear-gradient(90deg, #97df97 0%, #63cb63 100%);
    }
    .progress-future {
      display: flex;
      align-items: center;
      justify-content: center;
      background: linear-gradient(270deg, #a1a1a1 0%, #bfbfbf 100%);
    }
    .progress-scale {
      display: flex;
      width: 100%;
      .progress-scale-item {
        position: relative;
        font-size: 12px;
        .progress-scale-line {
          width: 1px;
          height: 6px;
          background-color: #999;
        }
        .progress-scale-son {
          position: absolute;
          left: -20%;
        }
      }
    }
    .marking-line {
      position: absolute;
      top: 50%;
      width: 0;
      height: 60%;
      border-left: 0.125rem solid #1890ff;
      transition: left 0.1s linear; /* 平滑过渡 */
      z-index: 2;
      transform: translateY(-50%);
      color: #1890ff;
    }
    .marking-line:after {
      content: '';
      position: absolute;
      top: -5px;
      right: -5px;
      width: 0;
      height: 0;
      border-left: 5px solid transparent;
      border-right: 5px solid transparent;
      border-top: 5px solid #1890ff;
    }
    .line-row1 {
      font-size: 12px;
      width: 90px;
      display: inline-block;
      position: absolute;
      bottom: -20px;
      left: -45px;
      text-align: center;
    }
    .line-row2 {
      font-size: 12px;
      width: 70px;
      display: inline-block;
      position: absolute;
      top: -20px;
      left: -35px;
      text-align: center;
    }
  }
}

.legend {
  display: flex;
  justify-content: flex-end;
  align-items: center;
  height: 32px;
  gap: 16px;

  .legend-item {
    display: flex;
    align-items: center;
    gap: 4px;

    .legend-dot {
      width: 10px;
      height: 10px;
    }

    .legend-text {
      font-size: 12px;
      color: #666;
    }
  }
}
</style>
